#ifndef _HUB75E_H_
#define _HUB75E_H_

/*
该项目由 davidzhu210开发和维护。联系方式：
Gitee: https://gitee.com/davidzhu210/projects
邮箱： davidzhu210@outlook.com
如果您对此项目有任何疑问、建议，或者发现了任何问题，非常欢迎通过以上方式与我联系！也欢迎提交 Issue 或 Pull Request。

部分代码参考：
https://github.com/SebiTimeWaster/ICN2053_ESP32_LedWall
*/

#include <Arduino.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>

class Panel {
   public:
    Panel(uint16_t width, uint16_t height, uint16_t scan_lines, const uint8_t* pins);
    void begin();
    void clearScreen();                                                                                                                   // 清除屏幕
    void setBackgound(uint8_t red8BitGray, uint8_t green8BitGray, uint8_t blue8BitGray);                                                  // 设置背景色
    void drawPixel(uint16_t posX, uint16_t posY, uint8_t red8BitGray, uint8_t green8BitGray, uint8_t blue8BitGray);                       // 声明 drawPixel 方法
    void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t red8BitGray, uint8_t green8BitGray, uint8_t blue8BitGray);  // 声明 drawLine 方法
    void drawRect(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t red8BitGray, uint8_t green8BitGray, uint8_t blue8BitGray);  // 声明 drawRect 方法
    void fillRect(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t red8BitGray, uint8_t green8BitGray, uint8_t blue8BitGray);  // 声明 fillRect 方法
    void drawCircle(uint16_t x0, uint16_t y0, uint16_t radius, uint8_t red8BitGray, uint8_t green8BitGray, uint8_t blue8BitGray);  // 声明 drawCircle 方法
    void fillCircle(uint16_t x0, uint16_t y0, uint16_t radius, uint8_t red8BitGray, uint8_t green8BitGray, uint8_t blue8BitGray);  // 声明 fillCircle 方法

    // 显示一个位图，可以是图形或汉字
    void diaplayBitmap(uint16_t posX, uint16_t posY, uint16_t bitmapWidth, uint16_t bitmapHeight, const uint8_t* bitmapData, const uint8_t* grayScale);

    // 绘制单个ASCII字符（8x16）
    void drawChar(uint16_t posX, uint16_t posY, char c, uint8_t r, uint8_t g, uint8_t b);
    // 绘制字符串（仅支持大写字母、数字、冒号、空格）
    void drawText(uint16_t posX, uint16_t posY, const char* text, uint8_t r, uint8_t g, uint8_t b);

    // 屏幕参数，全部为常量成员，构造时由外部传入。
    const uint16_t width;      // 显示宽度
    const uint16_t height;     // 显示高度
    const uint16_t scanLines;  // 扫描线数

   private:
    // HUB75E 面板的引脚定义，全部为常量成员，构造时由外部传入。
    // 这些引脚号用于直接操作 ESP32 的 GPIO，务必保证传入的 pins 数组在对象生命周期内有效，
    // 否则会导致野指针和崩溃。建议将 pins 数组拷贝到类的成员数组中，避免悬空指针问题。
    const uint8_t _PIN_CLK;  // 时钟引脚
    const uint8_t _PIN_LE;   // 锁存引脚
    const uint8_t _PIN_OE;   // 输出使能引脚
    const uint8_t _PIN_A;    // 行选地址 A
    const uint8_t _PIN_B;    // 行选地址 B
    const uint8_t _PIN_C;    // 行选地址 C
    const uint8_t _PIN_D;    // 行选地址 D
    const uint8_t _PIN_E;    // 行选地址 E
    const uint8_t _PIN_R1;   // 上半屏红色
    const uint8_t _PIN_G1;   // 上半屏绿色
    const uint8_t _PIN_B1;   // 上半屏蓝色
    const uint8_t _PIN_R2;   // 下半屏红色
    const uint8_t _PIN_G2;   // 下半屏绿色
    const uint8_t _PIN_B2;   // 下半屏蓝色

    uint32_t _displayNumberChips;

    // ICND2153AP寄存器配置值
    // bits |15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0|
    // Cfg1 | 0| 1| 0| 1| 1| 1| 1| 1| 0| 0| 0| 0| 0| 0| 0| 0| = 0x5FF0
    // Cfg2 | 0| 1| 1| 1| 1| 1| 1| 1| 1| 1| 1| 1| 1| 0| 1| 0| = 0x7FFE
    // Cfg3 | 0| 0| 1| 0| 0| 0| 0| 1| 1| 1| 1| 0| 0| 1| 1| 0| = 0x40F3
    // Cfg4 | 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| = 0x0000
    // Debug| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| = 0x0000
    const uint16_t _cfgValue[5] = {0x5FF0, 0x7FFE, 0x40F3, 0x0000, 0x0000};  // ICND2153AP寄存器配置值

    uint8_t _gpioPins[14];                           // 引脚数组，包含14个引脚编号，依次为 CLK, LE, OE, A, B, C, D, E, R1, G1, B1, R2, G2, B2
    uint8_t* _screenBuffer[2];  // 两个屏幕缓冲区，用于双缓冲
    uint32_t _displayBufferLineSize;    // 每扫描线字节数
    uint32_t _displayBufferSize;
    uint8_t* _canvas;                       // 指针型变量，指向画布内存，大小为 width * height * 3。每个元素是一个像素的 RGB 值（8位）
    unsigned char _activeScreenBuffer;  // 当前显示的屏幕缓冲区索引
    unsigned char _fps;                // 帧率，对用于3840刷新率

    void _setCfgValue();                                                   // 配置ICND2153AP寄存器
    void IRAM_ATTR _sendLatch(uint8_t clocks);                             // 发送锁存信号
    void IRAM_ATTR _digitalWriteFast(uint8_t pinNum, bool value);          // 快速设置GPIO引脚值
    void IRAM_ATTR _sendClock();                                           // 发送时钟信号
    void _sendConfiguration(uint16_t data, uint8_t latches);               // 发送ICND2153AP寄存器配置值
    void IRAM_ATTR _digitalWriteEvenFaster(uint32_t data, uint32_t mask);  // 快速设置多个GPIO引脚值
    void IRAM_ATTR _sendScanLine(unsigned char line);                      // 发送扫描线信号
    void IRAM_ATTR _sendPwmClock(unsigned char clocks);                    // 发送多个时钟信号

    // 缓存写入
    void _cacheWrite(unsigned char* buffer, unsigned int posX, unsigned int posY, unsigned char red, unsigned char green, unsigned char blue);
    void _refreshFrame();                          // 刷新屏幕缓冲区
    static void _dataTask(void* pvParameters);     // free RTOS任务，用于数据传输
    static void _refreshTask(void* pvParameters);  // free RTOS任务，用于刷新

    enum _fontSize {
        FONT_8X16,  // ASCII字符尺寸
    } fs;
};

#endif